package customerValidator

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"go-demo-2025/controllers"
	"go-demo-2025/utils/funcUtils"
)

// 添加客户数据前的参数校验
type ValidateDataExtra struct {
	City   string `json:"city" validate:"required" `        //非空
	Mobile string `json:"mobile" validate:"numeric,len=11"` //数字类型，长度为11
}
type ValidateData struct { //这里定义的结构体的字段需要和 model.User的结构体 保持一致
	Name      string              `json:"name" validate:"required"`        //非空
	Age       uint8               `json:"age" validate:"gte=0,lte=100"`    //0<=type<=100
	Email     string              `json:"email" validate:"required,email"` //非空，email格式
	ExtraData []ValidateDataExtra `json:"extra_data" validate:"dive"`      //dive关键字 表示 进入到嵌套结构体进行判断. 注意:这里必须用切片类型,传递的参数的extra节点也必须是个数组
}

func AddCustomerValidate() gin.HandlerFunc {
	return func(c *gin.Context) {
		//绑定需要校验的字段
		/*请求的参数示例:
		{
		    "name": "张小二",
		    "age": 123,
		    "email": "ddd@dd.com",
		    "extra_data": [ //注意: 这里必须是一个数组,而不能是对象
		        {
		            "city": "1",
		            "mobile": "234"
		        }
		    ]
		}
		*/

		//参数校验, 校验规则： https://github.com/go-playground/validator
		var requestData ValidateData
		if err := c.ShouldBindBodyWithJSON(&requestData); err != nil { //这里一定要用 ShouldBindBodyWithJSON,如果用 ShouldBindJSON只能绑定一次,二次绑定会报错:EOF
			errMsg := fmt.Sprintf("请求参数绑定错误: %v", err)
			fmt.Println(errMsg)
			controllers.ReturnError(c, 1001, errMsg)
			return
		}
		fmt.Println("requestData:", requestData)

		//参数校验
		validate := validator.New()
		if err := validate.Struct(requestData); err != nil {
			for _, e := range err.(validator.ValidationErrors) {
				errMsg := fmt.Sprintf("参数校验失败.错误的字段:%v,错误的值:%v,错误的tag:%v", e.Field(), e.Value(), e.Tag())
				fmt.Println(errMsg)
				controllers.ReturnError(c, 1001, errMsg)
				return
			}
		}

		//下面两种方式选择一种即可,这里为了列举多种可行性方案
		requestDataMap, _ := funcUtils.StructToMap(requestData, "json")
		c.Set("requestDataMap", requestDataMap) //将这里的数据转为map后传入下一步

		c.Set("requestData", requestData) //将这里的数据传入下一步
		c.Next()
	}
}
